use std::collections::HashMap;
use redis::{Connection, RedisResult};
use serde::{Deserialize, Serialize};
use sqlx::{MySql, MySqlPool, Pool};
use sqlx::mysql::MySqlConnectOptions;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
use void_log::*;

#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct Config {
    pub server_port: Option<i64>,
    pub database: Option<ConfigDatabase>,
    pub redis: Option<ConfigRedis>,
    pub sys_token: Option<String>,
}

#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct ConfigDatabase {
    pub url: Option<String>,
    pub port: Option<u16>,
    pub name: Option<String>,
    pub username: Option<String>,
    pub password: Option<String>,
}

#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct ConfigRedis {
    pub url: Option<String>,
    pub username: Option<String>,
    pub password: Option<String>,
    pub expire: Option<i64>,
}

impl Config {
    pub async fn get() -> Self {
        let mut yaml_file = File::open("config.yaml").await.expect("配置文件错误");
        let mut yaml_str = String::new();
        yaml_file.read_to_string(&mut yaml_str).await.expect("read str error");
        serde_yml::from_str::<Config>(&yaml_str).expect("config error")
    }

    ///
    ///
    /// # 数据库链接
    ///
    /// * `database`: 0 默认库, 1 OM数据库
    ///
    /// returns: Pool<MySql>
    ///
    /// # Examples
    ///
    /// ```
    /// get_sqlx_pool(0) 默认
    /// get_sqlx_pool(1) OM
    /// ```
    pub async fn get_sqlx_pool() -> Pool<MySql> {
        let config = Self::get().await;
        let database = config.database.unwrap_or_default();
        log_info!("{:?}", &database);
        let option = MySqlConnectOptions::new()
            .host(&database.url.unwrap_or("localhost".to_string()))
            .port(database.port.unwrap_or(3306))
            .username(&database.username.unwrap_or("root".to_string()))
            .password(&database.password.unwrap_or("1".to_string()))
            .database(&database.name.unwrap_or("modal".to_string()));
        MySqlPool::connect_with(option).await.expect("数据库链接失败")
    }

    pub async fn get_redis_conn() -> RedisResult<Connection> {
        let config = Self::get().await;
        let redis = config.redis.unwrap_or_default();
        let password = redis.password.unwrap_or_default();
        let password = urlencoding::encode(&password);
        let client = redis::Client::open(format!("redis://{}:{}@{}", &redis.username.unwrap_or_default(), password, &redis.url.unwrap_or_default()))?;
        let con = client.get_connection()?;
        Ok(con)
    }
}

pub fn parse_query_string(query: &str) -> HashMap<String, String> {
    query
        .split("&")
        .filter_map(|param| {
            let mut parts = param.splitn(2, "=");
            match (parts.next(), parts.next()) {
                (Some(key), Some(value)) => Some((key.to_string(), value.to_string())),
                _ => None,
            }
        })
        .collect()
}
